package service

import (
	"context"
	"encoding/json"
	"fmt"
	"log"
	"os"
	"strconv"

	"github.com/cloudwego/eino/components/tool"
	"github.com/cloudwego/eino/components/tool/utils"
	"github.com/cloudwego/eino/schema"
	"github.com/cloudwego/hertz/pkg/app/client"
	"github.com/cloudwego/hertz/pkg/app/middlewares/client/sd"
	"github.com/cloudwego/hertz/pkg/common/config"
	"github.com/cloudwego/hertz/pkg/protocol"
	"github.com/cloudwego/hertz/pkg/protocol/consts"
	"github.com/hertz-contrib/registry/eureka"
)

var hClient *client.Client // 用于发起 HTTP 请求的 Hertz 客户端

func init() {
	cli, err := client.NewClient()
	if err != nil {
		log.Fatalf("创建 Hertz 客户端失败: %v", err)
	}

	// 初始化 Eureka 客户端
	r := eureka.NewEurekaResolver([]string{os.Getenv("EUREKA_URL")})
	cli.Use(sd.Discovery(r))

	hClient = cli
}

// 获取服务地址
func getServiceURL(serviceName string) (string, error) {
	service := os.Getenv(serviceName)
	if service == "" {
		return "", fmt.Errorf("environment variable %s not set", serviceName)
	}
	return fmt.Sprintf("https://%s/", service), nil
}

// 为每个工具定义参数结构体，基于 API 文档

// GetProductListParams 定义 GetProductListTool 的参数。
type GetProductListParams struct {
	Page         int    `json:"page,omitempty"`         // 页码
	PageSize     int    `json:"pageSize,omitempty"`     // 每页大小
	CategoryName string `json:"categoryName,omitempty"` // 分类名称
}

// GetProductDetailParams 定义 GetProductDetailTool 的参数。
type GetProductDetailParams struct {
	ID string `json:"id"` // 商品ID (如果直接使用 InferTool，路径参数需要特殊处理)
}

// SearchProductParams 定义 SearchProductTool 的参数。
type SearchProductParams struct {
	Name string `json:"name"` // 搜索关键词
}

// AddToCartParams 定义 AddToCartTool 的参数。
type AddToCartParams struct {
	UserID int `json:"user_id"` // 用户ID
	Item   struct {
		ProductID int `json:"product_id"` // 商品ID
		Quantity  int `json:"quantity"`   // 数量
	} `json:"item"` // 商品信息
}

// GetProductListTool 创建一个获取商品列表的工具。
func GetProductListTool() tool.InvokableTool {
	f := func(ctx context.Context, params *GetProductListParams) (string, error) {
		if os.Getenv("ENV") == "dev" {
			mockResponse := `{
				"products": [
					{
						"id": 1,
						"name": "XX品牌降噪蓝牙耳机",
						"description": "高端降噪蓝牙耳机，采用先进降噪技术，舒适佩戴设计",
						"picture": "http://example.com/xx_headphone.jpg",
						"price": 999.99,
						"categories": ["electronics", "headphones", "bluetooth"]
					},
					{
						"id": 2,
						"name": "YY品牌舒适降噪耳机",
						"description": "主打舒适的降噪耳机，轻巧设计，长时间佩戴无压力",
						"picture": "http://example.com/yy_headphone.jpg",
						"price": 899.99,
						"categories": ["electronics", "headphones", "bluetooth"]
					}
				]
			}`
			return mockResponse, nil
		}

		req := protocol.AcquireRequest()
		resp := protocol.AcquireResponse()
		defer protocol.ReleaseRequest(req)
		defer protocol.ReleaseResponse(resp)

		baseUrl, err := getServiceURL("PRODUCT_SERVICE_NAME")
		if err != nil {
			return "", fmt.Errorf("获取服务地址失败: %w", err)
		}
		req.SetRequestURI(baseUrl + "product/list")
		req.Header.SetContentTypeBytes([]byte("application/json"))
		req.SetOptions(config.WithSD(true))
		q := req.URI().QueryArgs()
		if params != nil {
			if params.Page != 0 {
				q.Add("page", strconv.Itoa(params.Page))
			}
			if params.PageSize != 0 {
				q.Add("pageSize", strconv.Itoa(params.PageSize))
			}
			if params.CategoryName != "" {
				q.Add("categoryName", params.CategoryName)
			}
		}
		if err := hClient.Do(ctx, req, resp); err != nil {
			return "", fmt.Errorf("获取商品列表失败: %w", err)
		}

		return string(resp.Body()), nil
	}

	paramsOneOf, err := utils.GoStruct2ParamsOneOf[GetProductListParams]()
	if err != nil {
		panic(fmt.Errorf("为 GetProductListParams 生成 ParamsOneOf 失败: %w", err))
	}

	return utils.NewTool(&schema.ToolInfo{
		Name:        "get_product_list",
		Desc:        ToolsDescribtion["get_product_list"],
		ParamsOneOf: paramsOneOf,
	}, f)
}

// GetProductDetailTool 创建一个通过 ID 获取商品详情的工具。
func GetProductDetailTool() tool.InvokableTool {
	f := func(ctx context.Context, params *GetProductDetailParams) (string, error) {
		if os.Getenv("ENV") == "dev" {
			mockResponse := `{
				"product": {
					"id": 1,
					"name": "XX品牌降噪蓝牙耳机",
					"description": "高端降噪蓝牙耳机，采用先进降噪技术，舒适佩戴设计。特点：\n- 40dB深度降噪\n- 蓝牙5.2\n- 30小时续航\n- 轻量化设计\n- 智能触控",
					"price": 999.99,
					"categories": ["electronics", "headphones", "bluetooth"]
				}
			}`
			return mockResponse, nil
		}

		req := protocol.AcquireRequest()
		resp := protocol.AcquireResponse()
		defer protocol.ReleaseRequest(req)
		defer protocol.ReleaseResponse(resp)

		productID := params.ID
		if productID == "" {
			return "", fmt.Errorf("get_product_detail 工具需要商品 ID")
		}
		baseUrl, err := getServiceURL("PRODUCT_SERVICE_NAME")
		if err != nil {
			return "", fmt.Errorf("获取服务地址失败: %w", err)
		}
		req.SetRequestURI(baseUrl + fmt.Sprintf("product/%s", productID))
		req.Header.SetContentTypeBytes([]byte("application/json"))
		req.SetOptions(config.WithSD(true))

		if err := hClient.Do(ctx, req, resp); err != nil {
			return "", fmt.Errorf("获取商品ID %s 的详情失败: %w", productID, err)
		}

		return string(resp.Body()), nil
	}

	paramsOneOf, err := utils.GoStruct2ParamsOneOf[GetProductDetailParams]()
	if err != nil {
		panic(fmt.Errorf("为 GetProductDetailParams 生成 ParamsOneOf 失败: %w", err))
	}

	return utils.NewTool(&schema.ToolInfo{
		Name:        "get_product_detail",
		Desc:        ToolsDescribtion["get_product_detail"],
		ParamsOneOf: paramsOneOf,
	}, f)
}

// SearchProductTool 创建一个通过关键词搜索商品的工具。
func SearchProductTool() tool.InvokableTool {
	f := func(ctx context.Context, params *SearchProductParams) (string, error) {
		if os.Getenv("ENV") == "dev" {
			mockResponse := `{
				"results": [
					{
						"id": 1,
						"name": "XX品牌降噪蓝牙耳机",
						"description": "高端降噪蓝牙耳机，采用先进降噪技术，舒适佩戴设计",
						"picture": "http://example.com/xx_headphone.jpg",
						"price": 999.99,
						"categories": ["electronics", "headphones", "bluetooth"]
					},
					{
						"id": 2,
						"name": "YY品牌舒适降噪耳机",
						"description": "主打舒适的降噪耳机，轻巧设计，长时间佩戴无压力",
						"picture": "http://example.com/yy_headphone.jpg",
						"price": 899.99,
						"categories": ["electronics", "headphones", "bluetooth"]
					}
				]
			}`
			return mockResponse, nil
		}

		req := protocol.AcquireRequest()
		resp := protocol.AcquireResponse()
		defer protocol.ReleaseRequest(req)
		defer protocol.ReleaseResponse(resp)

		baseUrl, err := getServiceURL("PRODUCT_SERVICE_NAME")
		if err != nil {
			return "", fmt.Errorf("获取服务地址失败: %w", err)
		}
		req.SetRequestURI(baseUrl + "product/search")
		req.Header.SetContentTypeBytes([]byte("application/json"))
		req.SetOptions(config.WithSD(true))
		q := req.URI().QueryArgs()
		if params != nil {
			q.Add("name", params.Name)
		}

		if err := hClient.Do(ctx, req, resp); err != nil {
			return "", fmt.Errorf("搜索关键词 '%s' 的商品失败: %w", params.Name, err)
		}

		return string(resp.Body()), nil
	}

	paramsOneOf, err := utils.GoStruct2ParamsOneOf[SearchProductParams]()
	if err != nil {
		panic(fmt.Errorf("为 SearchProductParams 生成 ParamsOneOf 失败: %w", err))
	}

	return utils.NewTool(&schema.ToolInfo{
		Name:        "search_product",
		Desc:        ToolsDescribtion["search_product"],
		ParamsOneOf: paramsOneOf,
	}, f)
}

// AddToCartTool 创建一个将商品添加到购物车的工具。
func AddToCartTool() tool.InvokableTool {
	f := func(ctx context.Context, params *AddToCartParams) (string, error) {
		if os.Getenv("ENV") == "dev" {
			mockResponse := `{}`
			return mockResponse, nil
		}

		req := protocol.AcquireRequest()
		resp := protocol.AcquireResponse()
		defer protocol.ReleaseRequest(req)
		defer protocol.ReleaseResponse(resp)

		baseUrl, err := getServiceURL("CART_SERVICE_NAME")
		if err != nil {
			return "", fmt.Errorf("获取服务地址失败: %w", err)
		}
		req.SetRequestURI(baseUrl + "carts")
		req.Header.SetMethod(consts.MethodPost)
		req.Header.SetContentTypeBytes([]byte("application/json"))
		req.SetOptions(config.WithSD(true))

		if params != nil {
			bodyBytes, err := json.Marshal(params)
			if err != nil {
				return "", fmt.Errorf("序列化添加到购物车参数失败: %w", err)
			}
			req.SetBody(bodyBytes)
		}

		if err := hClient.Do(ctx, req, resp); err != nil {
			return "", fmt.Errorf("添加商品到购物车失败: %w", err)
		}

		return string(resp.Body()), nil
	}

	paramsOneOf, err := utils.GoStruct2ParamsOneOf[AddToCartParams]()
	if err != nil {
		panic(fmt.Errorf("为 AddToCartParams 生成 ParamsOneOf 失败: %w", err))
	}

	return utils.NewTool(&schema.ToolInfo{
		Name:        "add_to_cart",
		Desc:        ToolsDescribtion["add_to_cart"],
		ParamsOneOf: paramsOneOf,
	}, f)
}
